package com.aaaa.scheduler.util;

import com.aaaa.scheduler.objective.Objective;
import com.aaaa.scheduler.pojo.*;
import com.aaaa.scheduler.pojo.Process;
import com.aaaa.scheduler.rule.processrule.ProcessEDD;
import com.aaaa.scheduler.rule.processrule.ProcessRule;
import com.aaaa.scheduler.rule.processrule.ProcessSPT;
import com.aaaa.scheduler.scheduler.genetic.GeneticConfiguration;
import lombok.extern.slf4j.Slf4j;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartFrame;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.StandardChartTheme;
import org.jfree.chart.plot.Plot;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.XYShapeRenderer;
import org.jfree.data.xy.DefaultXYDataset;
import org.jfree.ui.RefineryUtilities;
import org.jfree.util.ShapeUtilities;
import tanling.matplot3d.app.facade.DotsDataProcessor;
import tanling.matplot3d.app.facade.Matplot3D4JMgr;
import tanling.matplot3d.common.Point3D;

import java.awt.*;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

@Slf4j
public class InstanceUtil {

    public static void outputSolutionStep(Process process){
        System.out.println("工单：" + process.getProduct().getName().replace("product:","")
                + "  工序：" + process.getName().replaceFirst("product:([0-9]+)&process:","")
                + "  开始时间：" + process.getStart() + "  结束时间：" + process.getFinish()
                + "  设备：" + process.getMachineName().replace("machine:",""));

//        System.out.print("当前的调度目标:");
//        for (Objective objective : instance.getObjectiveList()) {
//            System.out.print(objective.getObjectiveName() + ":" + objective.getObjectiveValue() + "     ");
//        }
//        System.out.println();
    }

    /**
     * 功能描述：将最后一代种群 画在坐标系中
     * TODO 按照rank分层 rank相等的连起来
     */
    public static void render2DGraph(final Chromosome[] population) {

        if (GeneticConfiguration.objectiveList.size() > 2) {
            System.out.println("\n\n超过两个目标不可以画在二维坐标系中！\n\n");
            return;
        }

//        GraphPlot graph = new GraphPlot(population);
//
//        graph.configurePlotter(GeneticConfiguration.X_AXIS_TITLE, GeneticConfiguration.Y_AXIS_TITLE);
//        graph.pack();
//
//        RefineryUtilities.centerFrameOnScreen(graph);
//
//        graph.setVisible(true);

        DefaultXYDataset xydataset = new DefaultXYDataset();

        //创建主题样式
        StandardChartTheme mChartTheme = new StandardChartTheme("CN");
        //设置标题字体
        mChartTheme.setExtraLargeFont(new Font("黑体", Font.BOLD, 20));
        //设置轴向字体
        mChartTheme.setLargeFont(new Font("宋体", Font.CENTER_BASELINE, 15));
        //设置图例字体
        mChartTheme.setRegularFont(new Font("宋体", Font.CENTER_BASELINE, 15));
        //应用主题样式
        ChartFactory.setChartTheme(mChartTheme);

        //根绝实际需求加载数据集到xydatasets中
        for (int l = 1; l <= 1; l++) {
            double[][] datas = new double[2][population.length];
            for (int i = 0; i < population.length; i++) {
                datas[0][i] = population[i].getObjectiveFitnessValueList().get(0);
                datas[1][i] = population[i].getObjectiveFitnessValueList().get(1);
            }
            xydataset.addSeries(l, datas);  //l为类别标签
        }

        JFreeChart chart = ChartFactory.createScatterPlot("种群分布", GeneticConfiguration.X_AXIS_TITLE,
                GeneticConfiguration.Y_AXIS_TITLE, xydataset, PlotOrientation.VERTICAL, true, false, false);
        ChartFrame frame = new ChartFrame("散点图", chart, true);

        frame.pack();
        frame.setVisible(true);
    }

    /**
     * 功能描述：根据数据集中的数据集 绘制所有代种群的分布情况
     *
     */
    public static void render2DGraphWithDataSets(final DefaultXYDataset xydataset) {

        if (GeneticConfiguration.objectiveList.size() > 2) {
            System.out.println("\n\n超过两个目标不可以画在二维坐标系中！\n\n");
            return;
        }

        //创建主题样式
        StandardChartTheme mChartTheme = new StandardChartTheme("CN");
        //设置标题字体
        mChartTheme.setExtraLargeFont(new Font("黑体", Font.BOLD, 20));
        //设置轴向字体
        mChartTheme.setLargeFont(new Font("宋体", Font.PLAIN, 15));
        //设置图例字体
        mChartTheme.setRegularFont(new Font("宋体", Font.PLAIN, 15));
        //应用主题样式
        ChartFactory.setChartTheme(mChartTheme);


        JFreeChart chart = ChartFactory.createScatterPlot("种群分布", GeneticConfiguration.X_AXIS_TITLE,
                GeneticConfiguration.Y_AXIS_TITLE, xydataset, PlotOrientation.VERTICAL, true, false, false);
        ChartFrame frame = new ChartFrame("散点图", chart, true);

        XYPlot plot = (XYPlot)chart.getPlot();
        //改变背景颜色
        plot.setBackgroundPaint(new Color(255,228,196));
        //改变每一组点的颜色   plot.getRenderer().setSeriesPaint(0, Color.black) ;
        int size = GeneticConfiguration.MAX_GENERATIONS/2;
        Color[] colors = new Color[size];
        Color c1 = Color.GREEN, c2 = Color.RED;
        for (int i = 0; i < colors.length; i++) {
            float ratio = (float)i / (float)colors.length;
            int red = (int)(c2.getRed() * ratio + c1.getRed() * (1 - ratio));
            int green = (int)(c2.getGreen() * ratio + c1.getGreen() * (1 - ratio));
            int blue = (int)(c2.getBlue() * ratio + c1.getBlue() * (1 - ratio));
            Color c = new Color(red, green, blue);
            colors[i] = c;
        }
        for (int i = 0; i < size; i++) {
            plot.getRenderer().setSeriesPaint(i, colors[i]);
            plot.getRenderer().setSeriesShape(i, ShapeUtilities.createDiamond((float) (0.08*size-0.08*i + 1)));
        }


        frame.pack();
        frame.setVisible(true);
    }


    /**
     * 功能描述：将所有代的种群绘制在三维坐标系中
     *
     */
    public static void render3DGraphWithDataSets(List<List<Point3D>> dataSet) {
        DotsDataProcessor processor = new DotsDataProcessor();

        final Matplot3D4JMgr mgr=new Matplot3D4JMgr(processor);

        //*************************************************************//
        //在此准备数据，将Point3D对象放入List<Point3D>容器中
        //prepare your data here
        //改变每一组点的颜色   plot.getRenderer().setSeriesPaint(0, Color.black) ;
//        int size = 10;
//        Color[] colors = new Color[size];
//        Color c1 = Color.RED, c2 = Color.GREEN;
//        for (int i = 0; i < colors.length; i++) {
//            float ratio = (float)i / (float)colors.length;
//            int red = (int)(c2.getRed() * ratio + c1.getRed() * (1 - ratio));
//            int green = (int)(c2.getGreen() * ratio + c1.getGreen() * (1 - ratio));
//            int blue = (int)(c2.getBlue() * ratio + c1.getBlue() * (1 - ratio));
//            Color c = new Color(red, green, blue);
//            colors[i] = c;
//        }
        int zeng = GeneticConfiguration.MAX_GENERATIONS/10;
        for (int i = 1; i <= dataSet.size(); i++) {
            //将数据加入处理器（可加入多组）
            processor.addData((i*zeng) + "", dataSet.get(i - 1));
        }
        //.................
        //*************************************************************//

        mgr.setSeeta(0.6);
        mgr.setBeita(1.0);

        mgr.setTitle("种群分布");
        mgr.setXName(GeneticConfiguration.X_AXIS_TITLE);
        mgr.setYName(GeneticConfiguration.Y_AXIS_TITLE);
        mgr.setZName(GeneticConfiguration.Z_AXIS_TITLE);
        //TODO 获取范围大小 自动生成缩放倍数
//        mgr.setScaleX(0.04);
//        mgr.setScaleY(1.0);
//        mgr.setScaleZ(0.02);

        //坐标参考平面不会遮挡数据
        mgr. setCoordianteSysShowType( Matplot3D4JMgr.COORDINATE_SYS_ALWAYS_FURTHER);
        mgr.setScatterPerspectiveType(true);

        mgr.show();
    }


    /**
     * 功能描述：打印调度结果 - 目标函数值
     *
     */
    public static void printResultSampleScheduler(Instance instance) {
        // TODO Auto-generated method stub
        System.out.println("\n\n**********************优先级调度规则的调度结果**********************");
        System.out.println("工序优先级调度规则    " + instance.getProcessComparator().getRuleName());
        System.out.println("设备选择规则         " + instance.getCandidateMachineRule().getRuleName());
        System.out.println("调度目标:");
        for (Objective objective : instance.getObjectiveList()) {
            System.out.println(objective.getObjectiveName() + ":" + objective.getObjectiveValue());
        }
        List<Machine> machineList = new ArrayList<>(instance.getMachineMap().values());
        Collections.sort(machineList, (o1, o2) -> {
            return o1.getID() - o2.getID();
        });
        for(Machine machine : machineList){
            System.out.println("设备"+machine.getName().replace("machine:","") + "的利用率:" + machine.getUtilRation());
//            System.out.println(machine.getName()+ "的利用率:" + machine.getUtilRation());
        }
    }


    /**
     * 功能描述：打印调度结果 - 目标函数值
     *
     */
    public static void printResultGAScheduler(Instance instance) {
        // TODO Auto-generated method stub
        System.out.println("\n\n**********************遗传算法的调度结果**********************");
        System.out.println("生成染色体的方式     " + instance.getChromosomeCreateName());
        System.out.println();
        System.out.println("调度目标:");
        for (Objective objective : instance.getObjectiveList()) {
            System.out.println(objective.getObjectiveName() + ":" + objective.getObjectiveValue());
        }
        System.out.println();

        List<Machine> machineList = new ArrayList<>(instance.getMachineMap().values());
        Collections.sort(machineList, (o1, o2) -> {
            return o1.getID() - o2.getID();
        });
        for(Machine machine : machineList){
            System.out.println("设备"+machine.getName().replace("machine:","") + "的利用率:" + machine.getUtilRation());
//            System.out.println(machine.getName()+ "的负荷:" + machine.getLoadRation());
        }
    }

    /**
     * 功能描述：绘制甘特图
     *
     */
    public static void printGante(Instance instance) {
        // 把这几个数据结构在 绘制甘特图的函数里 构造出来 。使得这个类的方法都是静态的
//        List<String> processName = new ArrayList<>();
//        List<Double> processStartTime = new ArrayList<>();
//        List<Double> processEndTime = new ArrayList<>();
//        List<String> productName = new ArrayList<>();
//        List<String> machineName = new ArrayList<>();

        System.out.println("\n\n**********************甘特图**********************");
        int sumTime = (int) calcCmax(instance);
        int[] time = new int[sumTime];
        int[][] gante = new int[instance.getMachineNum()][sumTime];
        for (Process process : instance.getProcessMap().values()) {
            int productNum = process.getProductID();
            int s = (int) (double) process.getStart();
            int e = (int) (double) process.getFinish();
            int m = process.getMachineID();
            for(int j=s+1; j<=e; j++){
                if(gante[m-1][j-1] != 0){
                    throw new RuntimeException();
                }
                gante[m-1][j-1] = productNum;
            }
        }
        //打印
        String t = "time:";
        String machine = "machine";
        for(int i=t.length(); i<machine.length()+2; i++){//补空格
            System.out.print(" ");
        }
        System.out.print(t);//时间坐标
        for(int i=0; i<sumTime; i++){//打印时间
            time[i] = i+1;
            if(time[i] < 10) System.out.print("  " + time[i]);
            else if(time[i] < 100) System.out.print(" " + time[i]);
        }
        System.out.println();
        for(int i=0; i<gante.length; i++){//打印每台设备的安排情况
            System.out.print(machine + "" + (i+1) + ":");
            for(int j=0; j<gante[0].length; j++){
                if(gante[i][j] != 0){
                    if(gante[i][j] < 10) System.out.print("  " + gante[i][j]);
                    else if(gante[i][j] < 100) System.out.print(" " + gante[i][j]);
                }
                else
                    System.out.print("   ");
            }
            System.out.println();
        }

    }
    /**
     *
     * @description: 计算当前制造期
     *
     */
    public static double calcCmax(Instance instance) {
        double cmax = 0;
//        for (Product product : instance.getProductMap().values()) {//用订单结束时间计算，只有有一个订单结束了才会计算
//            if (product.getFinish() > cmax) {
//                cmax = product.getFinish();
//            }
//        }
        //用设备使用情况计算
        for (Machine machine : instance.getMachineMap().values()) {
            for (Process process : machine.getQueueList()) {
                if(process.getFinish() > cmax)
                    cmax = process.getFinish();
            }
        }
        return cmax;
    }
    /**
     *
     * @description: 设置每台设备的利用率
     *
     */
    public static void setMachineUtilityAndLoad(Instance instance) {
        // 制造期
        double cmax = InstanceUtil.calcCmax(instance);
        // 利用率计算
        for (Machine machine : instance.getMachineMap().values()) {
            double util = 0;
            for (Process process : machine.getQueueList()) {
                util += process.getRunTime() * process.getPlanQty();
            }
            machine.setLoadRation(util);
            machine.setUtilRation(util / cmax);
        }
    }

    /**
     *
     * @description: 计算所有设备利用率的方差
     *
     */
    public static double calcUtility(Instance instance) {
        List<Double> utilities = new ArrayList<>();
        // 制造期
        double cmax = InstanceUtil.calcCmax(instance);
        // 利用率计算
        for (Machine machine : instance.getMachineMap().values()) {
            double util = 0;
            for (Process process : machine.getQueueList()) {
                util += process.getRunTime() * process.getPlanQty();
            }
            utilities.add(util / cmax);
        }
        double sum = 0, avg = 0, variance = 0;
        for (Double utility : utilities) {
            sum += utility;
        }
        avg = sum/utilities.size();
        for (Double utility : utilities) {
            variance += Math.pow(utility-avg, 2);
        }
        variance /= utilities.size();

        return variance;
    }

    /**
     * 功能描述：设置比较器
     *
     */
    public static void setProcessComparator(Instance instance, int actionId) throws Exception {
        // TODO Auto-generated method stub
        switch (actionId) {
            case ProcessRule.PART_ACTION_EDD:
                instance.setProcessComparator(new ProcessEDD());
                break;
            case ProcessRule.PART_ACTION_SPT:
                instance.setProcessComparator(new ProcessSPT());
                break;
            default:
                log.error("无法找到编号为" + actionId + "的规则，请先在此注册！");
                throw new Exception("无法找到编号为" + actionId + "的规则，请先在此注册！");
                // instance.setOperationComparator(new OperationSPT());
                // break;
        }
    }
    public static void setProcessComparator(Instance instance, ProcessRule processRule){
        instance.setProcessComparator(processRule);
    }



    public static void reportAlgorithmStart() {

        System.out.println("\n=============================================================");
        System.out.println("RUNNING ALGORITHM");
    }
    public static void reportDefaultConfiguration() {

        System.out.println("使用默认配置 . . .\n");
        InstanceUtil.reportConfiguration();
    }
    public static void reportCustomConfiguration() {

        System.out.println("使用自定义配置 . . .\n");
        InstanceUtil.reportConfiguration();
    }

    public static void reportConfiguration() {

        System.out.println("种群大小 : " + GeneticConfiguration.POPULATION_SIZE);
        System.out.println("遗传算法最大的进化迭代次数 : " + GeneticConfiguration.MAX_GENERATIONS);
        System.out.println("遗传算法交叉率 : " + GeneticConfiguration.CROSSOVER_PROBABILITY);
        System.out.println("遗传算法变异率 : " + GeneticConfiguration.MUTATION_PROBABILITY);
        System.out.println("X-坐标（目标1） : " + GeneticConfiguration.X_AXIS_TITLE);
        System.out.println("Y-坐标（目标2） : " + GeneticConfiguration.Y_AXIS_TITLE);
        if(GeneticConfiguration.Z_AXIS_TITLE != null)
            System.out.println("Z-坐标（目标3） : " + GeneticConfiguration.Z_AXIS_TITLE);
        if(GeneticConfiguration.W_AXIS_TITLE != null)
            System.out.println("W-坐标（目标4） : " + GeneticConfiguration.W_AXIS_TITLE);
        if(GeneticConfiguration.V_AXIS_TITLE != null)
            System.out.println("V-坐标（目标5） : " + GeneticConfiguration.V_AXIS_TITLE);
        System.out.println();
    }

    public static void reportCustomConfigurationStartInput() {
        System.out.println("使用你的自定义配置 . . .\n");
    }

    public static void reportWrongInput() {
        System.out.println("\n\n输入错误！程序退出！\n\n");
        throw new RuntimeException();
    }


}
